package com.odata.springboot.starter.odata.utils;

import com.odata.springboot.starter.odata.odata.config.OdataCachedData;
import com.odata.springboot.starter.odata.odata.sql.sqlBuild.OdataClassMetaData;
import org.apache.olingo.commons.api.data.Entity;
import org.apache.olingo.commons.api.data.Property;
import org.apache.olingo.commons.api.data.ValueType;
import org.apache.olingo.commons.api.edm.EdmPrimitiveTypeKind;
import org.apache.olingo.commons.api.edm.provider.CsdlEntityType;
import org.apache.olingo.commons.api.edm.provider.CsdlProperty;

import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import java.sql.Types;
import java.util.ArrayList;
import java.util.List;

/**
 * @author chenYX
 * @date 2021/6/30 14:54
 * @description
 */
public class OdataEntityUtils {


    /**
     * 处理一个结果集到entity
     * @author : yongxiang
     * @description :
     * @param
     * @date : 11:13 2021/7/1
    */
    public static Entity handleOne2Entity(ResultSet resultSet, Class<?> aClass) throws SQLException {

        OdataClassMetaData odataClassMetaData = OdataCachedData.getClassMetaDataByClass(aClass);
        if (resultSet.next()){
            return getEntity(resultSet,odataClassMetaData);
        }
        return null;
    }

    private static Entity getEntity(ResultSet resultSet, OdataClassMetaData odataClassMetaData) throws SQLException {
        Entity entity = new Entity();
        ResultSetMetaData metaData = resultSet.getMetaData();
        //处理
        for (int i = 1; i <= metaData.getColumnCount(); i++) {
            String columnName = metaData.getColumnName(i);
            String objectFieldName = odataClassMetaData.getObjectFiledByDataBaseField(columnName);
            Property property = resultSet2Property(resultSet, metaData, i, objectFieldName);
            entity.addProperty(property);
        }
        return entity;
    }

    /**
     * 处理多个结果集到entity
     * @author : yongxiang
     * @description :
     * @param
     * @date : 11:13 2021/7/1
     */
    public static List<Entity> handleMany2EntityList(ResultSet resultSet, Class aClass) throws SQLException {
        OdataClassMetaData odataClassMetaData = OdataCachedData.getClassMetaDataByClass(aClass);
        List<Entity> entities = new ArrayList<>();
        while (resultSet.next()){
            Entity entity = getEntity(resultSet,odataClassMetaData);
            entities.add(entity);
        }
        return entities;
    }




    /**
     *
     *数据库字段类型 ->> Property 的类型
     * @author : yongxiang
     * @description :
     * @param
     * @date : 10:08 2021/7/1
     */
    public static Property resultSet2Property(ResultSet rset, ResultSetMetaData rsmeta, int column,String columnName)
            throws SQLException {
        Property prop = null;
        switch (rsmeta.getColumnType(column)) {
            case Types.TINYINT:
                prop = new Property(null, columnName, ValueType.PRIMITIVE, rset.getByte(column));
                break;
            case Types.SMALLINT:
                prop = new Property(null, columnName, ValueType.PRIMITIVE, rset.getShort(column));
                break;
            case Types.INTEGER:
                prop = new Property(null, columnName, ValueType.PRIMITIVE, rset.getInt(column));
                break;
            case Types.BIGINT:
                prop = new Property(null, columnName, ValueType.PRIMITIVE, rset.getLong(column));
                break;
            case Types.DECIMAL:
                prop = new Property(null, columnName, ValueType.PRIMITIVE, rset.getBigDecimal(column));
                break;
            case Types.BOOLEAN:
                prop = new Property(null, columnName, ValueType.PRIMITIVE, rset.getBoolean(column));
                break;
            case Types.REAL:
                prop = new Property(null, columnName, ValueType.PRIMITIVE, rset.getFloat(column));
                break;
            case Types.DOUBLE:
                prop = new Property(null, columnName, ValueType.PRIMITIVE, rset.getDouble(column));
                break;
            case Types.DATE:
                prop = new Property(null, columnName, ValueType.PRIMITIVE, rset.getDate(column));
                break;
            case Types.TIMESTAMP:
                prop = new Property(null, columnName, ValueType.PRIMITIVE, rset.getTimestamp(column));
                break;
            case Types.TIME:
                prop = new Property(null, columnName, ValueType.PRIMITIVE, rset.getTime(column));
                break;
            case Types.CHAR:
            case Types.VARCHAR:
            default:
                prop = new Property(null, columnName, ValueType.PRIMITIVE, rset.getString(column));
                break;
        }
        return prop;
    }


    /**
     * 构建entityType
     *
     * @author : yongxiang
     * @description :
     * @param
     * @date : 11:36 2021/7/1
    */
    public static CsdlEntityType handleMetaData2EntityType(ResultSet resultSet, Class<?> aClass) throws SQLException {
        OdataClassMetaData odataClassMetaData = OdataCachedData.getClassMetaDataByClass(aClass);
        if (odataClassMetaData != null){
            CsdlEntityType csdlEntityType = new CsdlEntityType();
            //属性集合
            List<CsdlProperty> csdlProperties = new ArrayList<>();
            while (resultSet.next()){
                String columnName = resultSet.getString("COLUMN_NAME");
                String objectFiledName = odataClassMetaData.getObjectFiledByDataBaseField(columnName);
                if (!org.springframework.util.StringUtils.isEmpty(objectFiledName)){
                    CsdlProperty csdlProperty = resultSetMetaData2CsdlProperty(resultSet, objectFiledName);
                    if (csdlProperties != null){
                        csdlProperties.add(csdlProperty);
                    }
                }
            }
            csdlEntityType.setProperties(csdlProperties);
            return csdlEntityType;
        }
        return null;
    }




    public static CsdlProperty resultSetMetaData2CsdlProperty(ResultSet resultSet, String columnName)
            throws SQLException {
        CsdlProperty csdlProp = new CsdlProperty();
        int columnType = resultSet.getInt("DATA_TYPE");
        csdlProp.setName(columnName);
        switch (columnType) {
            case Types.TINYINT:
                csdlProp.setType(EdmPrimitiveTypeKind.SByte.getFullQualifiedName());
                break;
            case Types.SMALLINT:
                csdlProp.setType(EdmPrimitiveTypeKind.Int16.getFullQualifiedName());
                break;
            case Types.INTEGER:
                csdlProp.setType(EdmPrimitiveTypeKind.Int32.getFullQualifiedName());
                break;
            case Types.BIGINT:
                csdlProp.setType(EdmPrimitiveTypeKind.Int64.getFullQualifiedName());
                break;
            case Types.DECIMAL:
                csdlProp.setType(EdmPrimitiveTypeKind.Decimal.getFullQualifiedName());
                csdlProp.setScale(resultSet.getInt("COLUMN_SIZE"));
                csdlProp.setPrecision(resultSet.getInt("DECIMAL_DIGITS"));
                break;
            case Types.BOOLEAN:
                csdlProp.setType(EdmPrimitiveTypeKind.Boolean.getFullQualifiedName());
                break;
            case Types.REAL:
                csdlProp.setType(EdmPrimitiveTypeKind.Single.getFullQualifiedName());
                break;
            case Types.DOUBLE:
                csdlProp.setType(EdmPrimitiveTypeKind.Double.getFullQualifiedName());
                break;
            case Types.DATE:
                csdlProp.setType(EdmPrimitiveTypeKind.Date.getFullQualifiedName());
                break;
            case Types.TIMESTAMP:
                csdlProp.setType(EdmPrimitiveTypeKind.DateTimeOffset.getFullQualifiedName());
                break;
            case Types.TIME:
                csdlProp.setType(EdmPrimitiveTypeKind.TimeOfDay.getFullQualifiedName());
                break;
            case Types.CHAR:
            case Types.VARCHAR:
                csdlProp.setType(EdmPrimitiveTypeKind.String.getFullQualifiedName());
                csdlProp.setMaxLength(resultSet.getInt("COLUMN_SIZE"));
                break;
            default:
                csdlProp.setType(EdmPrimitiveTypeKind.String.getFullQualifiedName());
                break;
        }
        return csdlProp;
    }


}

